import copy
import json
import requests
from util.jiafu_log import JiaFuLogger

log_file = JiaFuLogger("jiafu_server:util:jiafu_rest_api")

CONNECT_TIMEOUT = 2  # 超时设定，单位秒


class RestApi:
    # _cookies = None
    _cookies = None

    def get_cookies(self):
        """
        返回浅拷贝的cookies，主要用于websocket连接时所需要的验证。
        :return: cookies
        """
        if self._cookies:
            return copy.copy(self._cookies)
        return self._cookies

    def set_cookies(self, cookies):
        """
        用于设置cookies
        :param cookies:
        :return:
        """
        self._cookies = cookies
        return self._cookies

    def __init__(self, url, callback=None):
        self.url = url
        if callback:
            self._callback = callback

    def set_callback(self, callback):
        self._callback = callback

    def __post__(self, method, **kwargs):
        params = {}
        for key in kwargs.keys():
            if kwargs[key]:
                params[key] = kwargs[key]
        URL = self.url + method + '/'
        try:
            if (self._cookies):
                res = requests.post(URL, data=params, cookies=self._cookies, timeout=CONNECT_TIMEOUT)
            else:
                return {'errno': -2, 'message': '请先登录'}
        except:
            return {'errno': -2, 'message': '网络请求问题，请稍后重试'}
        # 如果返回的不是200或者403，那么代表不可控的客户端或服务端错误。
        if (res.status_code != 200 and res.status_code != 403):
            log_file('errno_rest_res: %s' % str(res))
            return {'errno': -2, 'message': 'status_code is %s, please call engineer' % str(res.status_code)}
        try:
            dict_res = json.loads(res.text)
        except:
            return {'errno': -2, 'message': '错误返回'}
        return dict_res

    def __get__(self, method, **kwargs):
        params = {}
        for key in kwargs.keys():
            if kwargs[key]:
                params[key] = kwargs[key]
        URL = self.url + method + '/'
        try:
            if (self._cookies):
                res = requests.get(URL, params=params, cookies=self._cookies, timeout=CONNECT_TIMEOUT)
            else:
                res = requests.get(URL, params=params, timeout=CONNECT_TIMEOUT)
        except:
            return {'errno': -2, 'message': '网络请求问题，请稍后重试'}
        # 如果返回的不是200或者403，那么代表不可控的客户端或服务端错误。
        if (res.status_code != 200 and res.status_code != 403):
            log_file('errno_rest_res: %s' % str(res))
            return {'errno': -2, 'message': 'status_code is %s, please call engineer' % str(res.status_code)}
        return json.loads(res.text)

    def login(self, name, password):
        """
        登录，成功则记录cookies值使用
        :param name:
        :param password:
        :return:
        """
        login_url = self.url + 'login/'
        params = {'name': name, 'password': password}
        try:
            res = requests.post(login_url, data=params, timeout=CONNECT_TIMEOUT)
        except:
            return {'errno': -1, 'message': '网络请求问题，请稍后重试'}
        if (res.status_code != 200 and res.status_code != 403):
            log_file('errno_rest_res: %s' % str(res))
            return {'errno': -1, 'message': 'status_code is %s, please call engineer' % str(res.status_code)}
        data = json.loads(res.text)
        if data['errno'] == 0:
            self._cookies = requests.utils.dict_from_cookiejar(res.cookies)
        return data

    def logout(self, MTCallback):
        """
        登出,同时删除cookies值
        :return:
        """
        res = self.__post__('logout')
        self._cookies = None
        # return res
        self._callback(res, MTCallback)

    def system_status(self, MTCallback):
        """
        返回系统运行状态，客户端根据状态决定是否让⽤户交易。
        :return:返回结果status，有NORMAL正常，MAINTAINING维护中两个状态
        """
        res = self.__get__('system_status')
        # return res
        self._callback(res, MTCallback)

    def symbol(self, MTCallback, symbol):
        """
        查看币对的信息，在下订单前做校验使
        :param symbol:交易对
        :return:
        """
        res = self.__get__('symbol', symbol=symbol)
        # return res
        self._callback(res, MTCallback)

    def get_orders(self, MTCallback, status=None, page_num=None, page_size=None, order_by=None, start_date=None,
                   end_date=None):
        """
        :param status: 状态，可选值：OPEN，FINISH，ALL
        :param page_num: 页数
        :param page_size: 每页数量
        :param order_by: 排序方式，可选值：id，create_at
        :return:
        """
        # thread = threading.current_thread()
        # print("rest线程 %s" % thread.getName())
        res = self.__get__('get_orders', status=status, page_num=page_num, page_size=page_size, order_by=order_by,
                           start_date=start_date, end_date=end_date)
        # return res
        # if 'errno' in res.keys():
        #     if (res['errno'] == 0):
        #         list_data = res['data']
        #         for i in range(len(list_data)):
        #             data = list_data[len(list_data) - i - 1]
        #             self._callback(data, MTCallback)
        # else:
        #     log_file('big err no errno:%' % str(res))
        self._callback(res, MTCallback)

    def get_trades(self, MTCallback, page_num=None, page_size=None, start_date=None, end_date=None):
        """
        获取当前交易员的历史交易，默认按交易倒序返回
        :param page_num:
        :param page_size:
        :return:
        """
        res = self.__get__('get_trades', page_num=page_num, page_size=page_size, start_date=start_date, end_state=end_date)
        # if 'errno' in res.keys():
        #     if (res['errno'] == 0):
        #         list_data = res['data']
        #         for i in range(len(list_data)):
        #             data = list_data[len(list_data) - i - 1]
        #             self._callback(data, MTCallback)
        # else:
        #     log_file('big err no errno:%' % str(res))
        self._callback(res, MTCallback)

    def asset(self, MTCallback):
        """
        账户资产状况
        :return:
        """
        res = self.__get__('asset')
        # return res
        self._callback(res, MTCallback)

    def create_order(self, MTCallback, symbol, type, price, quantity, side, time_in_force=None, stop_price=None,
                     iceberg_qty=None):
        """
        创建订单
        :param symbol:市场
        :param type: 交易类型，可选值：限价单LIMIT，市价单MARKET
        :param price: 价格
        :param quantity: 数量
        :param side: 交易方，可选值：买BUY，卖SELL
        :return:
        """
        res = self.__post__('create_order', symbol=symbol, type=type, price=price, quantity=quantity, side=side,
                            time_in_force=time_in_force, stop_price=stop_price, iceberg_qty=iceberg_qty)
        # return res
        self._callback(res, MTCallback)

    def cancel_order(self, MTCallback, order_id):
        res = self.__post__('cancel_order', id=order_id)
        # return res
        self._callback(res, MTCallback)

    def cancel_pendding_orders(self, MTCallback, ids=None):
        """
        取消当前账户所有未结束挂单，包含新订单，部分成交订单
        :param ids: 订单ID集，如果不指定ID集，系统会找到所有新订单、部分成交订单取消。
        :return:
        """
        if ids:
            res = self.__post__('cancel_pendding_orders', ids=ids)
        else:
            res = self.__post__('cancel_pendding_orders')
        # return res
        self._callback(res, MTCallback)

    def get_order_books(self, MTCallback, symbol):
        """
        获取指定币对的报价深度
        :param symbol:
        :return:
        """
        res = self.__get__('get_order_books', symbol=symbol)
        # return res
        self._callback(res, MTCallback)

    def exchange_info(self, MTCallback):
        """
        :return:返回合法交易对相关信息。
        """
        res = self.__get__('exchange_info')
        # return res
        self._callback(res, MTCallback)

    def asset_stat(self,MTCallback,freq):
        res = self.__get__('asset_stat/'+freq)
        self._callback(res,MTCallback)

    def asset_log(self,MTCallback,type,start_date=None,end_date=None,page_num=None,page_size=None,order_by=None):
        res = self.__get__('asset/log',type=type,start_date=start_date,end_date=end_date,page_num=page_num,page_size=page_size,order_by=order_by)
        self._callback(res,MTCallback)

    def platform_trades(self,MTCallback,symbol,limit=None):
        res = self.__get__('platform/trades',symbol=symbol,limit=limit)
        self._callback(res,MTCallback)

# 使用范例
if __name__ == '__main__':
    from const import GZ_REST_BASE_URL
    restApi = RestApi(GZ_REST_BASE_URL)
    res = restApi.login(name='600003', password='123456')
    ret = restApi.__get__('get_order_books', symbol='BNBBTC')
    print(ret)
    print(len(ret["data"]))